﻿using System.Collections;
using System.Collections.Concurrent;
using NewLife;
using NewLife.Reflection;
using XCode.Configuration;

namespace XCode;

/// <summary>实体处理模块</summary>
public interface IEntityModule
{
    /// <summary>为指定实体类初始化模块，返回是否支持</summary>
    /// <param name="entityType"></param>
    /// <returns></returns>
    Boolean Init(Type entityType);

    /// <summary>创建实体对象</summary>
    /// <param name="entity"></param>
    /// <param name="forEdit"></param>
    void Create(IEntity entity, Boolean forEdit);

    /// <summary>验证实体对象</summary>
    /// <param name="entity"></param>
    /// <param name="isNew"></param>
    /// <returns></returns>
    Boolean Valid(IEntity entity, Boolean isNew);

    /// <summary>删除实体对象</summary>
    /// <param name="entity"></param>
    Boolean Delete(IEntity entity);
}

/// <summary>实体模块集合</summary>
public class EntityModules : IEnumerable<IEntityModule>
{
    #region 全局静态
    /// <summary></summary>
    public static EntityModules Global { get; } = new EntityModules(null);
    #endregion

    #region 属性
    /// <summary>实体类型</summary>
    public Type EntityType { get; set; }

    /// <summary>模块集合</summary>
    public IEntityModule[] Modules { get; set; } = new IEntityModule[0];
    #endregion

    #region 构造
    /// <summary>实例化实体模块集合</summary>
    /// <param name="entityType"></param>
    public EntityModules(Type entityType) => EntityType = entityType;
    #endregion

    #region 方法
    /// <summary>添加实体模块</summary>
    /// <param name="module"></param>
    /// <returns></returns>
    public virtual void Add(IEntityModule module)
    {
        // 异步添加实体模块，避免死锁。实体类一般在静态构造函数里面添加模块，如果这里同步初始化会非常危险
        ThreadPool.UnsafeQueueUserWorkItem(s => AddAsync(s as IEntityModule), module);
    }

    /// <summary>添加实体模块</summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public virtual void Add<T>() where T : IEntityModule, new() => Add(new T());

    private void AddAsync(IEntityModule module)
    {
        // 未指定实体类型表示全局模块，不需要初始化
        var type = EntityType;
        if (type != null && !module.Init(type)) return;

        lock (this)
        {
            var list = new List<IEntityModule>(Modules)
            {
                module
            };

            Modules = list.ToArray();
        }
    }

    /// <summary>创建实体时执行模块</summary>
    /// <param name="entity"></param>
    /// <param name="forEdit"></param>
    public void Create(IEntity entity, Boolean forEdit)
    {
        foreach (var item in Modules)
        {
            item.Create(entity, forEdit);
        }

        if (this != Global) Global.Create(entity, forEdit);
    }

    /// <summary>添加更新实体时验证</summary>
    /// <param name="entity"></param>
    /// <param name="isNew"></param>
    /// <returns></returns>
    public Boolean Valid(IEntity entity, Boolean isNew)
    {
        foreach (var item in Modules)
        {
            if (!item.Valid(entity, isNew)) return false;
        }

        if (this != Global) Global.Valid(entity, isNew);

        return true;
    }

    /// <summary>删除实体对象</summary>
    /// <param name="entity"></param>
    public Boolean Delete(IEntity entity)
    {
        foreach (var item in Modules)
        {
            if (!item.Delete(entity)) return false;
        }

        if (this != Global) Global.Delete(entity);

        return true;
    }
    #endregion

    #region IEnumerable<IEntityModule> 成员
    IEnumerator<IEntityModule> IEnumerable<IEntityModule>.GetEnumerator()
    {
        foreach (var item in Modules)
        {
            yield return item;
        }
    }
    #endregion

    #region IEnumerable 成员
    IEnumerator IEnumerable.GetEnumerator() => Modules.GetEnumerator();
    #endregion
}

/// <summary>实体模块基类</summary>
public abstract class EntityModule : IEntityModule
{
    #region IEntityModule 成员
    private readonly Dictionary<Type, Boolean> _Inited = new();
    /// <summary>为指定实体类初始化模块，返回是否支持</summary>
    /// <param name="entityType"></param>
    /// <returns></returns>
    public Boolean Init(Type entityType)
    {
        var dic = _Inited;
        if (dic.TryGetValue(entityType, out var b)) return b;
        lock (dic)
        {
            if (dic.TryGetValue(entityType, out b)) return b;

            return dic[entityType] = OnInit(entityType);
        }
    }

    /// <summary>为指定实体类初始化模块，返回是否支持</summary>
    /// <param name="entityType"></param>
    /// <returns></returns>
    protected virtual Boolean OnInit(Type entityType) => true;

    /// <summary>创建实体对象</summary>
    /// <param name="entity"></param>
    /// <param name="forEdit"></param>
    public void Create(IEntity entity, Boolean forEdit) { if (Init(entity?.GetType())) OnCreate(entity, forEdit); }

    /// <summary>创建实体对象</summary>
    /// <param name="entity"></param>
    /// <param name="forEdit"></param>
    protected virtual void OnCreate(IEntity entity, Boolean forEdit) { }

    /// <summary>验证实体对象</summary>
    /// <param name="entity"></param>
    /// <param name="isNew"></param>
    /// <returns></returns>
    public Boolean Valid(IEntity entity, Boolean isNew)
    {
        if (!Init(entity?.GetType())) return true;

        return OnValid(entity, isNew);
    }

    /// <summary>验证实体对象</summary>
    /// <param name="entity"></param>
    /// <param name="isNew"></param>
    /// <returns></returns>
    protected virtual Boolean OnValid(IEntity entity, Boolean isNew) => true;

    /// <summary>删除实体对象</summary>
    /// <param name="entity"></param>
    public Boolean Delete(IEntity entity)
    {
        if (!Init(entity?.GetType())) return true;

        return OnDelete(entity);
    }

    /// <summary>删除实体对象</summary>
    /// <param name="entity"></param>
    /// <returns></returns>
    protected virtual Boolean OnDelete(IEntity entity) => true;
    #endregion

    #region 辅助
    /// <summary>设置脏数据项。如果某个键存在并且数据没有脏，则设置</summary>
    /// <param name="fields"></param>
    /// <param name="entity"></param>
    /// <param name="name"></param>
    /// <param name="value"></param>
    /// <returns>返回是否成功设置了数据</returns>
    protected virtual Boolean SetNoDirtyItem(ICollection<FieldItem> fields, IEntity entity, String name, Object value)
    {
        var fi = fields.FirstOrDefault(e => e.Name.EqualIgnoreCase(name));
        if (fi == null) { return false; }
        name = fi.Name;
        if (!entity.IsDirty(name)) return entity.SetItem(name, value);
        return false;
    }

    /// <summary>如果是默认值则覆盖，无视脏数据，此时很可能是新增</summary>
    /// <param name="fields"></param>
    /// <param name="entity"></param>
    /// <param name="name"></param>
    /// <param name="value"></param>
    /// <returns>返回是否成功设置了数据</returns>
    protected virtual Boolean SetItem(ICollection<FieldItem> fields, IEntity entity, String name, Object value)
    {
        // 没有这个字段，就不想了
        var fi = fields.FirstOrDefault(e => e.Name.EqualIgnoreCase(name));
        if (fi == null) return false;
        name = fi.Name;
        // 如果是默认值则覆盖，无视脏数据，此时很可能是新增
        if (fi.Type.IsInt())
        {
            if (entity[name].ToLong() != 0) return false;
        }
        else if (fi.Type == typeof(String))
        {
            if (entity[name] is String str && !str.IsNullOrEmpty()) return false;
        }
        else if (fi.Type == typeof(DateTime))
        {
            if (entity[name] is DateTime dt && dt.Year > 2000) return false;
        }

        return entity.SetItem(name, value);
    }

    private static readonly ConcurrentDictionary<Type, FieldItem[]> _fieldNames = new();
    /// <summary>获取实体类的字段名。带缓存</summary>
    /// <param name="entityType"></param>
    /// <returns></returns>
    protected static FieldItem[] GetFields(Type entityType)
    {
        return _fieldNames.GetOrAdd(entityType, t => t.AsFactory().Fields);
    }
    #endregion
}